# -*- coding:utf-8 -*-
## author : cypro666
## note   : python3.4+
"""
file system operations on linux system
"""
import os, sys, threading, sched, time
from os.path import basename,dirname,realpath
from datetime import date
from .utilities import sysout
from .debug import print_exception


def userdir():
    """ return current user's dir """
    return os.path.expanduser('~') + os.sep


def get_file_time(fn):
    """ get file time : ctime, mtime, atime """
    from time import localtime
    assert os.path.exists(fn)
    fstat = os.lstat(fn)
    ct, mt, at = fstat.st_ctime, fstat.st_mtime, fstat.st_atime
    return (localtime(ct), localtime(mt), localtime(at))


class PathSpliter(object):
    """ split standard path stirng """
    def __init__(self, name):
        self._fname = name
        self._parts = tuple(os.path.realpath(name).split(os.sep))
    
    def exist(self)->bool:
        """ check exist or not """
        return os.path.exists(self._fname) 
    
    def __str__(self)->str:
        return self._fname

    def updir(self, n)->str:
        """ return a list of parent dirs """
        assert n >= 0
        if not n:
            return self._parts[-1]
        if abs(n) == len(self._parts) - 1:
            root = self._parts[0]
            return root if root else os.sep 
        return self._parts[-(n+1)]
    
    def __getitem__(self, n)->str:
        """ [] getter """
        assert n >= 0
        if not n:
            return os.sep.join(self._parts)
        if abs(n) == len(self._parts) - 1:
            root = self._parts[0]
            return root if root else os.sep 
        return os.sep.join(self._parts[:-n])



class PathWalker(threading.Thread):
    """ walking in path and call user's function with file names in path """
    def __init__(self, path, callback, delay, times):
        threading.Thread.__init__(self)
        assert path and callback and delay >= 0 and times >= 1
        sysout(path+'\n')
        if not os.path.exists(path):
            raise ValueError('PathWalker : no such dir : ' + path)
        self.__path = path
        self.__delay = delay
        self.__times = times
        self.__callback = callback
        self.daemon = True 

    def walk(self):
        """ walking impl """
        for root, dirs, filenames in os.walk(self.__path):
            try:
                if root[-1] != os.sep:
                    root += os.sep
                for fn in filenames:
                    self.__callback(root + fn)
                for d in dirs:
                    self.__callback(root + d)
            except Exception as e:
                print_exception('PathWalker.walk')

    def run(self):
        """ thread start """
        sc = sched.scheduler(time.time, time.sleep)
        for i in range(self.__times):
            sc.enter(self.__delay * (i+1), 1, self.walk)
        sc.run()



def is_valid_dir(*args) ->bool:
    """ check is valid dir """
    for d in args:
        assert isinstance(d, str)
        if not os.path.isdir(d):
            return False
        if d[0] in ('.', '~'):
            return False
    return True


def get_file_names(path, check, timeout=10)->list:
    """ get all file names in `path` """
    filenames = []
    def _callback(fn):
        if check(fn):
            sysout(fn + ' added to param list\n')
            filenames.append(fn)
    pw = PathWalker(path, _callback, timeout, 1)
    pw.start()
    pw.join(timeout)
    return filenames



DELETE_PRED = 5 

class FileGC(threading.Thread):
    """ experiment... """
    def __init__(self, path, delay, user_callback = lambda fn:fn.endswith('.log')):
        threading.Thread.__init__(self)
        self.user_callback = user_callback
        self.path = path
        self.delay = delay
        self.fnlist = set()
        self.deleted = set()
    
    def __callback(self, fn):
        if not self.user_callback(fn):
            return
        ct,mt,at = get_file_time(fn)
        tdelta = date.today() - date(ct.tm_year, ct.tm_mon, ct.tm_mday)
        if (tdelta.days >= DELETE_PRED):
            self.fnlist.add(fn)

    def run(self):
        while True:
            time.sleep(self.delay)
            self.fnlist.clear()
            PathWalker(self.path, self.__callback, 0, 1).walk()
            if not self.fnlist:
                continue
            for fn in self.fnlist:
                if os.path.exists(fn):
                    if os.path.isdir(fn):
                        os.removedirs(fn)
                    else:
                        os.remove(fn)
                    self.deleted.add(fn)
                    sysout('deleted: %s\n' % fn)
            # sysout("%s\n" % self.get_deleted())
    
    def get_deleted(self):
        return tuple(self.deleted)



def test(path):
    """"""
    print(userdir())
    from pprint import pprint
    ps = PathSpliter('/home/user/temp/domains.txt')
    print(str(ps)+'\n')
    print(ps.updir(0))
    print(ps.updir(1))
    print(ps.updir(2))
    print(ps.updir(3))
    print(ps.exist())
    print(ps[0])
    print(ps[1])
    print(ps[2])
    print(ps[3])

    c, m ,a = get_file_time(path)
    print(c.tm_year, c.tm_mon, c.tm_mday)
    cb = lambda fn : print(fn, time.ctime(os.path.getctime(fn)))
    pw = PathWalker(os.getcwd(), cb, 2.0, 1)
    pw.start()
    pw.join(3)
    sys.stdout.flush()
    sys.stderr.flush()

    cb = lambda fn : fn.endswith('fs_test.txt')
    fgc = FileGC(path, 5, cb)
    fgc.run()


if __name__ == '__main__':
    test(userdir() + 'share')



